package service

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	"github.com/xuri/excelize/v2"
	"net/url"
	cDto "ssadmin/common/query"
	"ssadmin/common/utils"
	"ssadmin/internal/admin/models/command"
	dto "ssadmin/internal/admin/models/query"
	"strconv"
	"strings"
	"time"

	"gitee.com/sansaniot/ssiot-core/httpmvc/service"
	"gorm.io/gorm"

	"ssadmin/internal/admin/models"
)

type SysDictData struct {
	service.Service
}

// GetPage 获取列表
func (e *SysDictData) GetPage(c *dto.SysDictDataGetPageReq, list *[]models.SysDictData, count *int64) error {
	var err error
	var data models.SysDictData

	err = e.Orm.Model(&data).
		Scopes(
			cDto.MakeCondition(c.GetNeedSearch()),
			cDto.OrderByCust("dict_sort", "ASC"),
			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
		).
		Find(list).Limit(-1).Offset(-1).
		Count(count).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return err
	}
	return nil
}

// Get 获取对象
func (e *SysDictData) Get(d *dto.SysDictDataGetReq, model *models.SysDictData) error {
	var err error
	var data models.SysDictData

	db := e.Orm.Model(&data).
		First(model, d.GetId())
	err = db.Error
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		err = errors.New("查看对象不存在或无权查看")
		e.Log.Errorf("db error: %s", err)
		return err
	}
	if db.Error != nil {
		e.Log.Errorf("db error: %s", err)
		return err
	}
	return nil
}

// Insert 创建对象
func (e *SysDictData) Insert(c *command.SysDictDataInsertReq) error {
	var err error
	var data = new(models.SysDictData)
	c.Generate(data)
	err = e.Orm.Create(data).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return err
	}
	return nil
}

// Update 修改对象
func (e *SysDictData) Update(c *command.SysDictDataUpdateReq) error {
	var err error
	var model = models.SysDictData{}
	e.Orm.First(&model, c.GetId())
	c.Generate(&model)
	db := e.Orm.Save(model)
	if err = db.Error; err != nil {
		e.Log.Errorf("db error: %s", err)
		return err
	}
	if db.RowsAffected == 0 {
		return errors.New("无权更新该数据")

	}
	return nil
}

// Remove 删除
func (e *SysDictData) Remove(c *command.SysDictDataDeleteReq) error {
	var err error
	var data models.SysDictData

	db := e.Orm.Delete(&data, c.GetId())
	if db.Error != nil {
		err = db.Error
		e.Log.Errorf("Delete error: %s", err)
		return err
	}
	if db.RowsAffected == 0 {
		err = errors.New("无权删除该数据")
		return err
	}
	return nil
}

// GetAll 获取所有
func (e *SysDictData) GetAll(c *dto.SysDictDataGetPageReq, list *[]models.SysDictData) error {
	var err error
	var data models.SysDictData

	err = e.Orm.Model(&data).
		Scopes(
			cDto.MakeCondition(c.GetNeedSearch()),
		).
		Find(list).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return err
	}
	return nil
}

// 导出变量
func (d *SysDictData) ExportDictData(c *gin.Context, m *models.SysDictData, req *dto.SysDictDataGetPageReq) error {
	req.PageIndex = 0
	list := make([]models.SysDictData, 0)
	err := d.Orm.Model(&m).
		Scopes(
			cDto.MakeCondition(req.GetNeedSearch()),
		).
		Find(&list).Limit(-1).Offset(-1).Error
	if err != nil {
		return err
	}
	if len(list) == 0 {
		return errors.New("查无数据")
	}
	// 生成模板
	f := excelize.NewFile()
	defer f.Close()
	// 模板内容
	if err := FillExportDictData(f, list); err != nil {
		return err
	}
	// 删除excelize的默认sheet
	f.DeleteSheet("Sheet1")
	// 响应文件流
	fileName := fmt.Sprintf("字典数据.xlsx")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename*=utf-8''%s", url.QueryEscape(fileName)))
	c.Header("File-Name", url.QueryEscape(fileName))
	c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8")
	if _, err := f.WriteTo(c.Writer); err != nil {
		_, _ = fmt.Fprintf(c.Writer, err.Error())
		return err
	}
	return nil
}

func (d *SysDictData) ImportDictData(c *gin.Context, m *models.SysDictData, req *dto.SysDictDataGetPageReq) error {
	// 获取文件对象
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		return err
	}
	if file == nil || !strings.HasSuffix(header.Filename, ".xlsx") {
		return errors.New("非法文件，请使用正确的文件导入")
	}
	defer file.Close()
	f, err := excelize.OpenReader(file)
	if err != nil {
		return err
	}
	// 执行导入
	if err = ImportDictData(m, f, req); err != nil {
		return err
	}
	return nil
}

/**
DictCode  string `json:"dictCode" gorm:"primaryKey;column:dict_code;comment:主键编码"`
	DictSort  int    `json:"dictSort" gorm:"size:20;comment:DictSort"`
	DictLabel string `json:"dictLabel" gorm:"size:128;comment:DictLabel"`
	DictValue string `json:"dictValue" gorm:"size:255;comment:DictValue"`
	DictType  string `json:"dictType" gorm:"size:64;comment:DictType"`
	CssClass  string `json:"cssClass" gorm:"size:128;comment:CssClass"`
	ListClass string `json:"listClass" gorm:"size:128;comment:ListClass"`
	IsDefault string `json:"isDefault" gorm:"size:8;comment:IsDefault"`
	Status    int    `json:"status" gorm:"size:4;comment:Status"`
	Default   string `json:"default" gorm:"size:8;comment:Default"`
	Remark    string `json:"remark" gorm:"size:255;comment:Remark"`
*/
var (
	DictDataHeaderName = []string{"显示名称", "字典值", "字典类型", "排序", "备注"}
	DictDataHeaderKey  = []string{"dictLabel", "dictValue", "dictType", "dictSort", "remark"}
)

// 导出内容填充
func FillExportDictData(f *excelize.File, dictDatas []models.SysDictData) error {
	// 头部单元格样式
	headerCellStyle, _ := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Bold: true,
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
		Border: []excelize.Border{
			{Type: "left", Color: "000000", Style: 1},
			{Type: "top", Color: "000000", Style: 1},
			{Type: "bottom", Color: "000000", Style: 1},
			{Type: "right", Color: "000000", Style: 1},
		},
	})
	sheetName := "字典数据"
	_, _ = f.NewSheet(sheetName)
	// 第1行
	_ = f.InsertRows(sheetName, 1, 1)
	colNum := len(DictDataHeaderName)
	for n := 0; n < colNum; n++ {
		axis, _ := excelize.ColumnNumberToName(n + 1)
		_ = f.SetCellValue(sheetName, axis+"1", DictDataHeaderName[n])
		_ = f.SetCellStyle(sheetName, axis+"1", axis+"1", headerCellStyle)
		_ = f.SetColWidth(sheetName, axis, axis, 20)
	}
	// 数据行起始
	startRow := 2
	size := len(DictDataHeaderKey)
	// 填充已有数据模型
	dictDatasSize := len(dictDatas)
	for row := startRow; row-startRow < dictDatasSize; row++ {
		_ = f.InsertRows(sheetName, row, 1)
		dictData := dictDatas[row-startRow]
		rowStr := strconv.Itoa(row)
		for colIndex := 0; colIndex < size; colIndex++ {
			key := DictDataHeaderKey[colIndex]
			axis, _ := excelize.ColumnNumberToName(colIndex + 1)
			//	DictDataHeaderKey  = []string{"dictLabel", "dictValue", "dictType", "dictSort", "remark"}
			switch key {
			case "dictLabel":
				_ = f.SetCellValue(sheetName, axis+rowStr, dictData.DictLabel)
				break
			case "dictValue":
				_ = f.SetCellValue(sheetName, axis+rowStr, dictData.DictValue)
				break
			case "dictType":
				_ = f.SetCellValue(sheetName, axis+rowStr, dictData.DictType)
				break
			case "dictSort":
				_ = f.SetColWidth(sheetName, axis, axis, 10)
				_ = f.SetCellValue(sheetName, axis+rowStr, dictData.DictSort)
				break
			case "remark":
				_ = f.SetColWidth(sheetName, axis, axis, 10)
				_ = f.SetCellValue(sheetName, axis+rowStr, dictData.Remark)
				break
			default:
				break
			}
		}
	}
	return nil
}

func ImportDictData(dictDataModel *models.SysDictData, f *excelize.File, req *dto.SysDictDataGetPageReq) error {
	sheetNum := f.SheetCount
	if sheetNum == 0 {
		return nil
	}
	// 解析
	dictDatas := make([]models.SysDictData, 0)
	errorInfo := ""
	for _, sheetName := range f.GetSheetList() {
		// 遍历
		rowIndexRead := make([]int, 0)
		//sheetErrPre := fmt.Sprintf("<br>(sheet: %s)<br>", sheetName)
		headerNames := DictDataHeaderName
		headerKeys := DictDataHeaderKey
		// 按行获取[][]单元格值，f.Rows迭代器不能过滤掉空内容的行
		rows, err := f.GetRows(sheetName)
		if err != nil {
			fmt.Println(err)
		}
		cols, err := f.GetCols(sheetName)
		if err != nil {
			fmt.Println(err)
		}
		maxRowNumber := len(rows)
		maxColNumber := len(cols)
		if maxRowNumber <= 1 {
			errorInfo += fmt.Sprintf("模板内容为空(sheet:%s)", sheetName)
			continue
		}
		if maxColNumber != len(headerNames) {
			return errors.New("无效的导入文件，请重新导出文件填写内容")
		}
		for rowIndex, rowColumns := range rows {
			if utils.GetCommUtil().IntIn(rowIndex, rowIndexRead) {
				// 效率优化 (每sheet中 遍历过的行跳过)
				continue
			}
			if rowIndex == 0 {
				rowIndexRead = append(rowIndexRead, rowIndex)
				continue
			}
			// 第2行起 为数据内容 解析行数据
			rowIndexRead = append(rowIndexRead, rowIndex)
			dictData := models.SysDictData{}
			for colNum, rowValue := range rowColumns {
				//	DictDataHeaderKey  = []string{"dictLabel", "dictValue", "dictType", "dictSort", "remark"}
				key := headerKeys[colNum]
				switch key {
				case "dictLabel":
					dictData.DictLabel = rowValue
					break
				case "dictValue":
					dictData.DictValue = rowValue
					break
				case "dictType":
					dictData.DictType = rowValue
					break
				case "dictSort":
					dictSort, ok := strconv.Atoi(rowValue)
					if ok == nil {
						dictData.DictSort = dictSort
					}
					break
				case "remark":
					dictData.Remark = rowValue
					break
				default:
					break
				}

			}
			dictDatas = append(dictDatas, dictData)
		}
		if len(errorInfo) > 0 {
			return errors.New(errorInfo)
		}
		for i, v := range dictDatas {
			//查找是否存在
			req.DictType = v.DictType
			req.DictLabel = v.DictLabel
			list := make([]models.SysDictData, 0)
			err = dictDataModel.Orm.Model(dictDataModel).
				Scopes(
					cDto.MakeCondition(req.GetNeedSearch()),
				).
				Find(&list).Limit(-1).Offset(-1).Error
			if err != nil {
				errorInfo += fmt.Sprintf("查询字典数据异常(rowIndex:%d)", i)
				return errors.New(errorInfo)
			}
			//存在则更新
			//"dictLabel", "dictValue", "dictType", "dictSort", "remark"
			if len(list) > 0 {
				oldModel := list[0]
				oldModel.DictLabel = v.DictLabel
				oldModel.DictValue = v.DictValue
				oldModel.DictType = v.DictType
				oldModel.DictSort = v.DictSort
				oldModel.Remark = v.Remark
				oldModel.UpdatedAt = time.Now()
				err = dictDataModel.Orm.Model(&dictDataModel).Where("dict_code = ?", oldModel.DictCode).Updates(&oldModel).Error
				if err != nil {
					errorInfo += fmt.Sprintf("更新字典数据异常(rowIndex:%d)", i)
					return errors.New(errorInfo)
				}
			} else {
				//不存在则插入
				oldModel := models.SysDictData{}
				oldModel.DictLabel = v.DictLabel
				oldModel.DictValue = v.DictValue
				oldModel.DictType = v.DictType
				oldModel.DictSort = v.DictSort
				oldModel.Status = 1
				oldModel.SystemId = req.SystemId
				oldModel.Remark = v.Remark
				oldModel.DictCode = uuid.NewV4().String()
				oldModel.CreatedAt = time.Now()
				oldModel.UpdatedAt = time.Now()
				err = dictDataModel.Orm.Model(&dictDataModel).Create(&oldModel).Error
				if err != nil {
					errorInfo += fmt.Sprintf("新增字典数据异常(rowIndex:%d)", i)
					return errors.New(errorInfo)
				}
			}
		}
	}
	return nil
}
